/*----------------------------------------------------------------------------
 * Copyright (c) <2016-2020>, <Huawei Technologies Co., Ltd>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior written
 * permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *---------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
 * Notice of Export Control Law
 * ===============================================
 * Huawei LiteOS may be subject to applicable export control laws and regulations, which might
 * include those applicable to Huawei LiteOS of U.S. and the country in which you are located.
 * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such
 * applicable export control laws and regulations.
 *---------------------------------------------------------------------------*/
#include "ble.h"
#include "ble_uart.h"
#include "osal.h"
#include "securec.h"
#include "los_task.h"
#include "los_queue.h"
unsigned char mtu = 20;
unsigned int ble_error = 0;
unsigned char TX_buffer[bufferLen];
ble_rx_buffer ble_RX;
ble_respond_frame ble_rx_respond_frame;
ble_set_query_frame ble_rx_set_query;

ble_log_level g_ble_log_level = BLE_DETAIL;
//UINT32 bleQueue;
#define CIRCLE_INDEX(a) ((a)>=bufferLen?((a)%bufferLen):(a))

int32_t ble_crc16_ccitt_table[] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a,
    0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b,
    0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528,
    0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719,
    0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e,
    0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf,
    0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec,
    0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd,
    0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2,
    0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3,
    0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0,
    0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691,
    0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806,
    0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37,
    0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64,
    0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55,
    0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
                          };

int32_t ble_calc_crc16(int32_t reg_init, const unsigned char *massage, int len)
{
    int32_t crc_reg = 0;
    int i = 0;
    crc_reg = reg_init;
    for(i = 0; i < len; i++)
    {
        crc_reg = (ble_crc16_ccitt_table[((crc_reg >> 8) ^ massage[i]) & 0xff] ^ (crc_reg << 8)) & 0xffff;
    }
    return crc_reg;
}

void ble_receive_byte(unsigned char data)
{
    if(CIRCLE_INDEX(ble_RX.data_tail + 1) == ble_RX.data_head)
    {
        ble_error = 1;
    }
    else
    {
        ble_RX.ble_buffer[ble_RX.data_tail] = data;
        ble_RX.data_len++;
        ble_RX.data_tail = CIRCLE_INDEX(ble_RX.data_tail+1);
    }
}
int ble_clean_rx_data(unsigned int number)
{
    int ret = 0;
    ble_printf(BLE_DEBUG, "ble_clean_rx_data_number: %u: ", number);
    for(int i = 0; i < number;i++)
    {
        ble_printf(BLE_DEBUG, " %02X",ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + i)]);
    }
    ble_printf(BLE_DEBUG, "\r\n");
    if(ble_RX.data_len > 0)
    {
        if(number <= ble_RX.data_len)
        {
            ble_RX.data_len -= number;
            ble_RX.data_head = CIRCLE_INDEX(ble_RX.data_head + number);
        }
        else
        {
            ble_error = 2;
            ret = -1;
        }
    }
    return ret;
}
int ble_clean_frame(unsigned char cmd)
{
    int ret = 0;
    if(cmd == 0x20)
    {
        ble_rx_set_query.cmd = 0;
        ble_rx_set_query.crc =0;
        ble_rx_set_query.dataNumber = 0;
        ble_rx_set_query.messageId = 0;
        ble_rx_set_query.recvLen = 0;
        ble_rx_set_query.sendMode = 0;
        ble_rx_set_query.totalSection = 0;
        ble_rx_set_query.useSpace = 0;
        ret = 1;
    }
    else if (ret == 0x30)
    {
        ble_rx_respond_frame.cmd = 0;
        ble_rx_respond_frame.errorCode = 0;
        ble_rx_respond_frame.messageId = 0;
        ble_rx_respond_frame.status = 0;
        ret = 1;
    }
    return ret;
}
int ble_data_section_info(unsigned int dataLen, unsigned char *useSpace, unsigned int *totalSection)
{
    int ret = 0;
    if((dataLen + 2) % (mtu - 3) == 0)
    {
        *totalSection = (dataLen + 2) / (mtu - 3);
    }
    else
    {
        if((dataLen + 2) % (mtu - 3) == 1)
        {
            *useSpace = 1;
        }
        *totalSection = (dataLen + 2) / (mtu - 3) + 1;
    }
    return ret;
}
int ble_pick_rx_frame(unsigned char dataLen)
{
    int ret = 0;
    dataLen -= 2;
    unsigned char cmd = 0;
    int32_t check_crc = 0;
    if(dataLen >= 8)
    {
        if((ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 7)] == 0XF7) && \
            (ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 8)] == 0XBE))
        {
            cmd = ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 9)];
        }
    }
    if((dataLen == 19) && (cmd & 0XF0) == 0X30)
    {
        /*
         *  7                          respond frame                             20
         *  -----------------------------------------------------------------------
         * |  frame start  |   cmd   |  messageId  | errorCode |  status  |  crc   |
         * |-----------------------------------------------------------------------|
         * |     0XF7BE    |  1 Byte |    4 Byte   |   4Byte   |  1 Byte  | 2 Byte |
         *  -----------------------------------------------------------------------
        */
        unsigned short crc = 0;
        crc = ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 19)];
        crc = (crc << 8) | ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 20)];
         // should check crc here
        ble_clean_frame(0X30);
        ble_rx_respond_frame.cmd = cmd;
        ble_rx_respond_frame.status = ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 18)];

        ble_rx_respond_frame.errorCode = (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 14)] << 24;
        ble_rx_respond_frame.errorCode |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 15)] << 16;
        ble_rx_respond_frame.errorCode |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 16)] << 8;
        ble_rx_respond_frame.errorCode |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 17)];

        ble_rx_respond_frame.messageId = (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 10)] << 24;
        ble_rx_respond_frame.messageId |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 11)] << 16;
        ble_rx_respond_frame.messageId |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 12)] << 8;
        ble_rx_respond_frame.messageId |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 13)];

        ret = 0X30;
    }
    else if((dataLen >= 18) && ((cmd & 0XF0) == 0X20 || (cmd & 0XF0) == 0X10))//without mtu
    {
        /*
         *  7                      set or query frame head                    19       21
         *  -----------------------------------------------------------------------------
         * | frame start |   cmd   | sendMode | messageId | dataNumber |   mtu  |   crc  |
         * |-----------------------------------------------------------------------------|
         * |    0XF7BE   |  1 Byte |  1 Byte  |   4 Byte  |   3 Byte   | 2 Byte | 2 Byte |
         *  -----------------------------------------------------------------------------
        */
         //V1.2 without mtu otherwise should refresh mtu here
        //(cmd & 0XF0) == 0X20 ? mtu = 60 : mtu = 20;
        unsigned int dataNumber = 0;
        dataNumber = (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 15)] << 16;
        dataNumber |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 16)] << 8;
        dataNumber |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 17)];
        if(dataNumber < oneFrameDataSize)
        {
            ble_clean_frame(0X20);
            ble_data_section_info(dataNumber, &ble_rx_set_query.useSpace, &ble_rx_set_query.totalSection);
            ble_printf(BLE_INFO, "ble_pick_rx_frame:useSpace=%02x\r\n",ble_rx_set_query.useSpace);
            ble_printf(BLE_INFO, "ble_pick_rx_frame:totalSection=%04x\r\n", ble_rx_set_query.totalSection);
            ble_rx_set_query.cmd = cmd;
            ble_printf(BLE_INFO, "ble_pick_rx_frame:cmd=%02x\r\n",ble_rx_set_query.cmd);
            ble_rx_set_query.sendMode = ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 10)];
            ble_printf(BLE_INFO, "ble_pick_rx_frame:sendMode=%02x\r\n",ble_rx_set_query.sendMode);
            ble_rx_set_query.messageId = (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 11)] << 24;
            ble_rx_set_query.messageId |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 12)] << 16;
            ble_rx_set_query.messageId |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 13)] << 8;
            ble_rx_set_query.messageId |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 14)];
            ble_printf(BLE_INFO, "ble_pick_rx_frame:messageId=%u\r\n",ble_rx_set_query.messageId);
            ble_rx_set_query.dataNumber = dataNumber;
            ble_printf(BLE_INFO, "ble_pick_rx_frame:dataNumber=%04x\r\n",ble_rx_set_query.dataNumber);
            ble_rx_set_query.crc = (unsigned short)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 18)] << 8;
            ble_rx_set_query.crc |= ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 19)];
            ble_printf(BLE_INFO, "ble_pick_rx_frame:crc=%04x\r\n",ble_rx_set_query.crc);
        }
        else
        {
            ble_error = 6;
        }
    }
    else if(10 <= dataLen && dataLen <= mtu + 5 && ble_rx_set_query.recvLen != ble_rx_set_query.dataNumber)
    {
        /*  7                        set or query frame body && tail                   26
         *  -----------------------------------------------------------------------------
         * |  sectionNumber  |                            data               : frame end |
         * |-----------------------------------------------------------------------------|
         * |      3 Byte     |                         (mtu-3) Byte                      |
         * |-----------------------------------------------------------------------------|
         * |      3 Byte     |                 (mtu-5) Byte                  |   0XBEBE  |
         *  -----------------------------------------------------------------------------
        */
        unsigned int sectionNumber = 0;
        sectionNumber = (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 7)] << 16;
        sectionNumber |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 8)] << 8;
        sectionNumber |= (unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 9)];

        unsigned char *dataStart = ble_rx_set_query.data + sectionNumber * (mtu - 3);

        if( sectionNumber < ble_rx_set_query.totalSection - 1) //body frame
        {
            if((ble_rx_set_query.useSpace == 1) && (sectionNumber == ble_rx_set_query.totalSection - 2))
            {
                for(int i=10; i < dataLen + 1; i++)
                {
                    *dataStart = ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + i)];
                    dataStart++;
                    ble_rx_set_query.recvLen++;
                }
                if(ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + dataLen + 1)] != 0X20)
                {
                    ble_error = 4;
                }
            }
            else
            {
                for(int i=10; i < dataLen + 2; i++)
                {
                    *dataStart = ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + i)];
                    dataStart++;
                    ble_rx_set_query.recvLen++;
                }
            }
        }
        else if(sectionNumber == ble_rx_set_query.totalSection - 1) //tail frame
        {
            for(int i=10; i < dataLen; i++)
            {
                *dataStart = ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + i)];
                dataStart++;
                ble_rx_set_query.recvLen++;
            }
            if((ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + dataLen)] != 0XBE) || \
                    (ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + dataLen+1)] != 0XBE))
            {
                ble_error = 5;
            }
        }
        ble_printf(BLE_INFO, "ble_pick_rx_frame:sectionNumber=%04x\r\n", sectionNumber);
        ble_printf(BLE_INFO, "ble_pick_rx_frame:recvLen=%04x\r\n", ble_rx_set_query.recvLen);
        if(ble_rx_set_query.recvLen == ble_rx_set_query.dataNumber)
        {
            check_crc = ble_calc_crc16(0, ble_rx_set_query.data, ble_rx_set_query.dataNumber);
            if(check_crc == ble_rx_set_query.crc)
            {
                ret = ble_rx_set_query.cmd & 0XF0;
            }
            else
            {
                ble_clean_frame(0X20);
                ble_printf(BLE_ERROR, "ble_crc_error:crc=%04x checkcrc=%04x\r\n", (unsigned int)ble_rx_set_query.crc, (unsigned int)check_crc);
            }
        }
    }
    return ret;
}
int ble_send_array(unsigned char *array, unsigned int len)
{
    int ret =0;
    for (int i = 0; i < len; i++)
    {
        ble_printf(BLE_INFO, " %02x", *array);
        ble_send_byte(*array);
        array++;
    }
    ret = 1;
    return ret;
}
int ble_send_frame(unsigned char *array, unsigned int len)
{
    int ret =0;
    unsigned char ble_TX_start[6] = {0X1C, 0XFF, 0X10, 0X00, 0X11, 0X00};
    ble_TX_start[2] = len + 2;
    ble_printf(BLE_INFO, "ble_send_frame: ");
    ble_send_array(ble_TX_start, 6);
    ble_send_array(array, len);
    ble_printf(BLE_INFO, "\r\n");
    LOS_TaskDelay(50);
    return ret;
}

int ble_api_send(unsigned int messageId, unsigned char cmd, unsigned char *data, unsigned int len)
{
    int ret = 0;
	unsigned char errcode[16] ={0};
    unsigned char crc[2] = {0X00, 0X00};
    unsigned char frameTpye = cmd & 0XF0;
	if(!data) data =errcode; //数据缺省为错误码: 0
    if(frameTpye == 0X20 || frameTpye == 0X10)
    {
        /*  7                      set or query frame head                    19       21
         *  -----------------------------------------------------------------------------
         * | frame start |   cmd   | sendMode | messageId | dataNumber |   mtu  |   crc  |
         * |-----------------------------------------------------------------------------|
         * |    0XF7BE   |  1 Byte |  1 Byte  |   4 Byte  |   3 Byte   | 2 Byte | 2 Byte |
         *  -----------------------------------------------------------------------------
         * |  sectionNumber  |                            data               : frame end |
         * |-----------------------------------------------------------------------------|
         * |      3 Byte     |                         (mtu-3) Byte                      |
         * |-----------------------------------------------------------------------------|
         * |      3 Byte     |                 (mtu-5) Byte                  |   0XBEBE  |
         *  -----------------------------------------------------------------------------
        */
        unsigned int totalSection = 0;
        unsigned char useSpace = 0;  //1 use
        unsigned char sendMode = 0x01;  //0x1 0x2

        ble_data_section_info(len ,&useSpace ,&totalSection);
        ble_printf(BLE_INFO, "len:%u useSpace: %02x totalSection: %02x\r\n", len, useSpace, totalSection);
        //frameStart
        TX_buffer[0] = 0XF7;
        TX_buffer[1] = 0XBE;
        TX_buffer[2] = cmd;
        //sendMode
        TX_buffer[3] = sendMode;
        TX_buffer[4] = (unsigned char)(messageId >> 24);
        TX_buffer[5] = (unsigned char)(messageId >> 16);
        TX_buffer[6] = (unsigned char)(messageId >> 8);
        TX_buffer[7] = (unsigned char)messageId;
        TX_buffer[8] = (unsigned char)(len >> 16);
        ble_printf(BLE_INFO, "send len0 %02x\r\n", TX_buffer[8]);
        TX_buffer[9] = (unsigned char)(len >> 8);
        ble_printf(BLE_INFO, "send len1 %02x\r\n", TX_buffer[9]);
        TX_buffer[10] = (unsigned char)len;
        ble_printf(BLE_INFO, "send len2 %02x\r\n", TX_buffer[10]);
        //mtu 2 byte
        TX_buffer[11] = crc[0];
        TX_buffer[12] = crc[1];
        ble_send_frame(TX_buffer, 13);
        unsigned int i;
        for(i = 0; i< totalSection; i++)
        {
            TX_buffer[0] = (unsigned char)(i >> 16) ;
            TX_buffer[1] = (unsigned char)(i >> 8) ;
            TX_buffer[2] = (unsigned char)i;
            if(i < totalSection -1)
            {
                for(int n = 0; n < mtu-3; n++)
                {
                    if((useSpace == 1) && (i == totalSection - 2) && (n == mtu - 4))
                    {
                        TX_buffer[3 + n] = 0X20;
                    }
                    else
                    {
                        TX_buffer[3 + n] = *data;
                    }
                    data++;
                }
                ble_send_frame(TX_buffer, mtu);
            }
            else if(i == totalSection -1)
            {
                unsigned int last = (len + useSpace) - i * (mtu - 3);
                for(int n = 0; n < last; n++)
                {
                    TX_buffer[3 + n] = *data;
                    data++;
                }
                TX_buffer[3 + last] = 0XBE;
                TX_buffer[3 + last + 1] = 0XBE;
                ble_send_frame(TX_buffer, 5 + last);
            }
        }
    }
    else if(frameTpye == 0X30)
    {
        // frameStart | cmd | messageId | errorCode | status | crc |
        TX_buffer[0] = 0XF7;
        TX_buffer[1] = 0XBE;
        TX_buffer[2] = cmd;
        TX_buffer[3] = (unsigned char)(messageId >> 24);
        TX_buffer[4] = (unsigned char)(messageId >> 16);
        TX_buffer[5] = (unsigned char)(messageId >>8);
        TX_buffer[6] = (unsigned char)messageId;
        TX_buffer[7] = (unsigned char)(*data >> 24);
        TX_buffer[8] = (unsigned char)(*data >> 16);
        TX_buffer[9] = (unsigned char)(*data >> 8);
        TX_buffer[10] = (unsigned char)*data;
        TX_buffer[11] = 0X00;
        TX_buffer[12] = crc[0];
        TX_buffer[13] = crc[1];
        ble_send_frame(TX_buffer, 14);
    }
    else
    {
        ret = ble_send_array(data, len);
    }
    return ret;
}
int ble_api_recv(unsigned int *messageId, unsigned char *cmd, unsigned char *data, unsigned int len)
{
    int ret = 0;
    unsigned char dataLen = ble_RX.data_len;
    unsigned char pickLen = 0;
    if(ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head)] == 0XFF && dataLen > 1)
    {
        pickLen = ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 1)] + 2;
        if(pickLen > (bufferLen -1))
        {
            ble_printf(BLE_ERROR, "ble: too long data");
            ble_clean_rx_data(1);
            ble_error = 7;
        }
        else if(dataLen >= pickLen)
        {
            ble_printf(BLE_INFO, "ble_api_recv: ");
            for(int i = 0; i < pickLen; i++)
            {
                ble_printf(BLE_INFO, " %02X",(unsigned int)ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + i)]);
            }
            ble_printf(BLE_INFO, "\r\n");
            ret = ble_pick_rx_frame(pickLen);
            ble_printf(BLE_INFO, "ble_pick_rx_frame:ret=%04x\r\n", ret);
            if(ret == 0X10 || ret == 0X20)
            {
                if(memcpy_s(data, len, ble_rx_set_query.data, ble_rx_set_query.dataNumber) == EOK)
                {
                    *cmd = ble_rx_set_query.cmd;
                    *messageId = ble_rx_set_query.messageId;
                    ret = ble_rx_set_query.dataNumber;
                }
                else
                {
                    ret = -1;
                    ble_error = 3;
                }
                ble_clean_frame(0X20);
            }
            else if(ret == 0X30)
            {
                if(memcpy_s(data, len, &ble_rx_respond_frame, sizeof(ble_rx_respond_frame)) == EOK)
                {
                    *cmd = ble_rx_respond_frame.cmd;
                    ret = sizeof(ble_rx_respond_frame);
                }
                else
                {
                    ret = -1;
                    ble_error = 3;
                }
                ble_clean_frame(0X30);
            }
            ble_clean_rx_data(pickLen);
        }
    }
    else if(ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head)] != 0XFF && dataLen > 0)
    {
        ble_clean_rx_data(1);
    }
    if(ble_error > 0)
    {
        ble_printf(BLE_ERROR, "ble_error: %u data_len: %u\r\n", ble_error, ble_RX.data_len);
        ble_printf(BLE_ERROR, "data_head: %u data_tail: %u\r\n", ble_RX.data_head, ble_RX.data_tail);
        ble_printf(BLE_ERROR, "data0= %02X data1= %02X", ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head)], \
            ble_RX.ble_buffer[CIRCLE_INDEX(ble_RX.data_head + 1)]);
        ble_error = 0;
    }
    return ret;
}
int ble_init(void)
{
    int ret =0;
    ble_RX.data_head = 0;
    ble_RX.data_tail = 0;
    ble_RX.data_len = 0;
    ble_rx_set_query.data = NULL;
    ble_rx_set_query.data = osal_malloc(oneFrameDataSize);
    if(ble_rx_set_query.data == NULL)
    {
        ble_error = 4;
        ble_printf(BLE_EMGENCY, "ble_osal_malloc_error: %u\r\n", ble_error);
        ret = -1;
    }
    return ret;
}
